package com.net.lnk.rpc.http.proxy;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mortbay.jetty.handler.AbstractHandler;

import com.net.lnk.rpc.http.container.RpcContainer;
import com.net.lnk.rpc.http.container.http.HttpContainer;
import com.net.lnk.rpc.http.exception.RpcException;
import com.net.lnk.rpc.http.exception.RpcExceptionEnum;
import com.net.lnk.rpc.http.invoke.ProviderConfig;
import com.net.lnk.rpc.http.serialize.RpcFormater;
import com.net.lnk.rpc.http.serialize.RpcRequest;
import com.net.lnk.rpc.http.serialize.json.JsonRpcFormater;

/**
 * 将需要暴露的接口及其实现bean装载到容器中，继承AbstractHandler处理请求
 */
public class ProviderProxyFactory extends AbstractHandler {

	/**
	 * 暴露的接口和实现bean的容器
	 */
	private Map<Class<?>, Object> providers = new ConcurrentHashMap<Class<?>, Object>();

	/**
	 * JSON格式化工具
	 */
	private RpcFormater formater = JsonRpcFormater.formater;

	/**
	 * 构造HTTP监听器
	 * 
	 * @param providers
	 */
	public ProviderProxyFactory(Map<Class<?>, Object> providers) {
		if (RpcContainer.container == null) {
			new HttpContainer(this).start();
		}

		registerInterface(providers);
	}

	/**
	 * 构造指定端口的HTTP监听容器
	 * 
	 * @param providers
	 * @param providerConfig
	 */
	public ProviderProxyFactory(Map<Class<?>, Object> providers, ProviderConfig providerConfig) {
		if (RpcContainer.container == null) {
			new HttpContainer(this, providerConfig).start();
		}

		registerInterface(providers);
	}

	public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
			throws IOException, ServletException {
		// 1.获取请求参数
		String requestString = request.getParameter("requestBody");
		try {
			// 2.解析请求参数，包含接口类，方面名，参数
			RpcRequest rpcRequest = formater.parseRequest(requestString);
			Class<?> interfaceClass = rpcRequest.getInterfaceClass();
			String method = rpcRequest.getMethod();
			Object[] parameter = rpcRequest.getParameter();
			// 3.取得被调用接口的实例bean
			Object bean = providers.get(interfaceClass);
			if (bean == null) {
				throw new RpcException(RpcExceptionEnum.NO_BEAN_FOUND.getCode(), interfaceClass);
			}
			// 4.获取参数类型
			Class<?>[] parameterClazzes = null;
			if (parameter != null && parameter.length > 0) {
				parameterClazzes = new Class<?>[parameter.length];
				for (int i = 0; i < parameter.length; i++) {
					parameterClazzes[i] = parameter[i].getClass();
				}
			}
			Object result = null;
			// 5.反射调用
			if (parameterClazzes == null) {
				result = interfaceClass.getMethod(method).invoke(bean);
			} else {
				result = interfaceClass.getMethod(method, parameterClazzes).invoke(bean, parameter);
			}
			String responseJson = "";
			// 6.格式化执行结果
			if (result != null) {
				responseJson = formater.formateResponse(result);
			}
			// 7.将结果写到输出流
			OutputStream outputStream = response.getOutputStream();
			outputStream.write(responseJson.getBytes("UTF-8"));
			outputStream.flush();
		} catch (RpcException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 注册暴露的接口和实现bean
	 */
	private void registerInterface(Map<Class<?>, Object> providers) {
		for (Map.Entry<Class<?>, Object> entry : providers.entrySet()) {
			this.providers.put(entry.getKey(), entry.getValue());
		}
	}

}
